//
// XAPI
//
// implement a api set to do some special thing. such as:
//    call special function XAPI_DispatchCall
//    make other process as api set psl service(YAPI) XAPI_SetYAPIHandlProc
//

#include <windows.h>
//#define IN_KERNEL
#include "kernel.h"

#define XAPI_IMP
#include "RPC.hxx"
#include "XAPI.h"

void DoMapPtr(LPVOID *P);
void UpdateCallerInfo (PTHREAD pth, BOOL fInKMode);

#ifndef LINK_KERNLE
#include "XAPIKLib.c"
#endif



//
// XAPI functions
//
int XAPI_DispatchCall(HANDLE hProc, DWORD dwAddr, DWORD dwParaNumb, ParaInfo* pPara);
int XAPI_SetYAPIHandlProc(HANDLE hAPISet, HANDLE hProc);
int XAPI_GetZone(DWORD* pdwZone);
int XAPI_SetZone(DWORD dwZone);

PFNVOID XAPI_Methods[] = 
{
	(PFNVOID)0,
	(PFNVOID)XAPI_DispatchCall,
	(PFNVOID)XAPI_SetYAPIHandlProc,
	(PFNVOID)XAPI_GetZone,
	(PFNVOID)XAPI_SetZone,
};

CINFO cinfXAPI = 
{
    "XAPI",
    DISPATCH_I_KPSL,
    0,
    sizeof(XAPI_Methods)/sizeof(XAPI_Methods[0]),
    XAPI_Methods,
};


DWORD g_dwXAPIZone=1;
#define XAPI_ZONE_WARNNING	(g_dwXAPIZone&(1<<0))
#define XAPI_ZONE_INFO 		(g_dwXAPIZone&(1<<1))

int XAPI_Init()
{
	if(NULL!=SystemAPISets[SH_LASTRESERVED+1])
	{
		RETAILMSG (XAPI_ZONE_WARNNING, (L"XAPI_Init no api stubs to install faild!\r\n"));
		return XAPI_INIT_FAILD;
	}

	SystemAPISets[SH_LASTRESERVED+1]=&cinfXAPI;
	return 0;
}

void SwitchToTgtProc(CALLSTACK* pcstk, PPROCESS pProc)
{
	pcstk->pprcLast = pCurProc;
	pcstk->akyLast = CurAKey;
//!? if set retAddr to 0 the call stack info can't be displayed by pb, why!? 
//	pcstk->retAddr = 0;
pcstk->retAddr = pCurThread->pcstkTop->retAddr;
	pcstk->dwPrevSP = 0;
	pcstk->pcstkNext = pCurThread->pcstkTop;
	pcstk->dwPrcInfo = 0;
	pCurThread->pcstkTop = pcstk;
	pCurThread->pProc = pProc;
	AddAccess(&pCurThread->aky, pProc->aky);
	SetCPUASID(pCurThread);
	UpdateCallerInfo (pCurThread, TRUE);
	SetNKCallOut (pCurThread);
}


int XAPI_DispatchCall(HANDLE hProc, DWORD dwAddr, DWORD dwParaNumb, ParaInfo* pPara)
{
	PPROCESS pProc;
	DWORD paraS[12];
    CALLSTACK cstk;

	DWORD i,dwCallRet;
	int ret=0;

	RETAILMSG (XAPI_ZONE_INFO, (L"XAPI_DispatchCall hProc:0x%x dwAddr:0x%x dwParaNumb:0x%x!\r\n", hProc, dwAddr, dwParaNumb) );

	// check handle
    if (!(pProc = HandleToProc(hProc)))
    {
		RETAILMSG (XAPI_ZONE_WARNNING, (L"XAPI_DispatchCall invalid handle:0x%x!\r\n", hProc));
        return XAPI_INVALIDE_HANDLE;
    }

	// deal para
	for(i=0; i<dwParaNumb; i++)
	{
		if(PARA_TYPE_PTR==pPara[i].type)
		{
			DoMapPtr((LPVOID*)(&((LPVOID)pPara[i].para)));
		}

		paraS[i]=pPara[i].para;
	}
	
	//switch to target proc
	SwitchToTgtProc(&cstk, pProc);
	
	// call function
//    try {
		dwCallRet=CallFun(dwAddr, dwParaNumb, paraS);
//    } except (EXCEPTION_EXECUTE_HANDLER) {
//		DEBUGMSG (1, (L"XAPI_DispatchCall call function exception!\r\n"));
//		ret=XAPI_CALL_EXCEPTION;
//    }

	//switch back
    SwitchBack();
	
	return ret;	
}


int XAPI_SetYAPIHandlProc(HANDLE hAPISet, HANDLE hProc)
{
	APISET* pAS;
	PROCESS* pProc;
	
	if( (pAS=HandleToAPISet(hAPISet))
		&& (pProc=HandleToProc(hProc)) )
	{
        pAS->cinfo.pServer = pProc;
        return 0;
	}
	
	RETAILMSG (XAPI_ZONE_WARNNING, (L"XAPI_SetYAPIHandlProc invalid handle:0x%x!\r\n", hAPISet));

	return XAPI_INVALIDE_HANDLE;

}

int XAPI_GetZone(DWORD* pdwZone)
{
	if(NULL!=pdwZone)
	{
		*pdwZone=g_dwXAPIZone;
		return 0;
	}
	
	return XAPI_INVALIDE_PARA;
}

int XAPI_SetZone(DWORD dwZone)
{
	g_dwXAPIZone=dwZone;
	return 0;
}

DWORD WINAPI CallFun(DWORD dwFnAddr, DWORD dwParaDwNumb, DWORD* pdwParaS)
{
	switch (dwParaDwNumb)
	{
	case 0:
		return (*((DWORD (*)())(dwFnAddr)))();

	case 1:
		return (*((DWORD (*)(DWORD))(dwFnAddr)))(pdwParaS[0]);

	case 2:
		return (*((DWORD (*)(DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1]);

	case 3:
		return (*((DWORD (*)(DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2]);

	case 4:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3]);

	case 5:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4]);

	case 6:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5]);

	case 7:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6]);

	case 8:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6], pdwParaS[7]);

	case 9:
		return (*((DWORD (*)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD))(dwFnAddr)))(pdwParaS[0], pdwParaS[1], pdwParaS[2], pdwParaS[3], pdwParaS[4], pdwParaS[5], pdwParaS[6], pdwParaS[7], pdwParaS[8]);

	// not implement, raise a exception
	default:
		return (*((DWORD (*)())(0)))();
	}
	
}
